/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CPOO;

/**
 *
 * @author Tomek
 */
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;

public class HistogramEQ {

	private static BufferedImage original, equalized,histogram_or,histogram_eq;
	 
    public static void mainHP(String[] args) throws IOException {
        
        String output = args[0];    //"C:/Users/Michał/Documents/NetBeansProjects/HistogramEQ/sunflower";
        File original_f = new File(output+".jpg");
        original = ImageIO.read(original_f);
        histogram_or = histogramDraw(output);
        equalized = histogramEqualization(original);
        writeImage(output+"_histogram",histogram_or);
        writeImage(output+"_eq",equalized);
        histogram_eq = histogramDraw(output+"_eq");
        writeImage(output+"histogram"+"_eq",histogram_eq);
 
    }
 
    private static void writeImage(String output, BufferedImage im) throws IOException {
        File file = new File(output+".jpg");
        ImageIO.write(im, "jpg", file);
    }
    
    
    public static BufferedImage histogramDraw(String output){
        System.out.printf("output: " ,output);
        BufferedImage picture=null;
        File imageFile = new File(output);
        try {
            picture = ImageIO.read(imageFile);
        } catch (IOException e) {
            System.err.println("Blad odczytu obrazka");
        }
        
        int width = picture.getWidth();
        int height = picture.getHeight();
        int[][] r = new int [width][height];
        int[][] g = new int [width][height];
        int[][] b = new int [width][height];
        int[] hist_R = new int[256];
        int[] hist_G = new int[256];
        int[] hist_B = new int[256];
        int[] hist_max_value = new int[256];
        
        for(int x=0;x<width;x++){                                        
        for(int y=0;y<height;y++){
            r[x][y] = (picture.getRGB(x,y) &0x00ff0000)>>16;  //odczytanie skladowych koloru
            g[x][y] = (picture.getRGB(x,y)&0x0000ff00)>>8;
            b[x][y] = (picture.getRGB(x,y)&0x000000ff);
            
            hist_R[(r[x][y])]++;                            //statystyka dla histogramu
            hist_G[(g[x][y])]++;
            hist_B[(b[x][y])]++;
        }
    }
             
        int max = 0;
        for(int i=0;i<256;i++){        
            if(hist_R[i] > max){
            max = hist_R[i];
        }
            if(hist_G[i] > max){
                max = hist_G[i];
            }
            if (hist_B[i] > max){
                max = hist_G[i];
            }
    }
        
        for(int i=0;i<256;i++){                     
            if(max > 511){                          //skalowanie
            hist_R[i] = (int)(hist_R[i]*512/max);
            hist_G[i] = (int)(hist_G[i]*512/max);
            hist_B[i] = (int)(hist_B[i]*512/max);
            }
            if((hist_R[i] >= hist_G[i])&&(hist_R[i] >= hist_B[i])){
                hist_max_value[i] = hist_R[i];
                    }
            if((hist_G[i] >= hist_R[i]) && (hist_G[i] >= hist_B[i])){
                hist_max_value[i] = hist_G[i];    
                    }
            if((hist_B[i] >= hist_R[i]) && (hist_B[i] >= hist_G[i])){
                hist_max_value[i] = hist_B[i];    
                    }
        }
              
        BufferedImage histogram = new BufferedImage(256, 512, picture.getType());
        
        for(int i=0;i<256;i++){
        for(int h=0;h<512;h++){
            int roznica = 511-hist_max_value[i];
            if(h>roznica){
            histogram.setRGB( i, h, 0);
            }
            else{
            histogram.setRGB( i, h,0xffffff);
            }
        }
        }
        
        /*                              sprawdzenie poprawnosci obliczen
        for(int i=0;i<256;i++){
        System.out.println("Wartosc hist_max_value nr "+i+": "+hist_max_value[i]);
        System.out.println("Wartosc hist nr "+i+": "+hist_R[i]+" "+hist_G[i]+" "+hist_B[i]);
        }
        */
        return histogram;           
    }
    
    
    public static BufferedImage histogramEqualization(BufferedImage original) {
 
        int red;
        int green;
        int blue;
        int newPixel = 0;
 
        // Pobranie tablicy lut
        ArrayList<int[]> histLUT = histogramEqualizationLUT(original);
 
        BufferedImage histogramEQ = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());
 
        for(int i=0; i<original.getWidth(); i++) {
            for(int j=0; j<original.getHeight(); j++) {
 
                // 
                red = new Color(original.getRGB (i, j)).getRed();
                green = new Color(original.getRGB (i, j)).getGreen();
                blue = new Color(original.getRGB (i, j)).getBlue();
 
                // Ustawia nowe wartosci pixeli
                red = histLUT.get(0)[red];
                green = histLUT.get(1)[green];
                blue = histLUT.get(2)[blue];
 
                // Zwraca scalone pixele
                newPixel = colorToRGB(red, green, blue);
 
                // ustawia wartosci kazdego pixela
                histogramEQ.setRGB(i, j, newPixel);
 
            }
        }
 
        return histogramEQ;
 
    }
 
    // Zwraca tablice lut dla kazdego z kolorow
    private static ArrayList<int[]> histogramEqualizationLUT(BufferedImage input) {
 
        // Zwraca histogramy red, green i blue
        ArrayList<int[]> imageHist = imageHistogram(input);
        
        // Tablica lut
        ArrayList<int[]> imageLUT = new ArrayList<int[]>();
 
        int[] rhistogram = new int[256];
        int[] ghistogram = new int[256];
        int[] bhistogram = new int[256];
 
        for(int i=0; i<rhistogram.length; i++) rhistogram[i] = 0;
        for(int i=0; i<ghistogram.length; i++) ghistogram[i] = 0;
        for(int i=0; i<bhistogram.length; i++) bhistogram[i] = 0;
 
        long sumr = 0;
        long sumg = 0;
        long sumb = 0;
       
 
        // Wyliczanie elementow tablicy lut z algorytmu na wyrownywanie histogramu

        float scale_factor = (float) (255.0 / (input.getWidth() * input.getHeight()));
        
        
        
        for(int i=0; i<rhistogram.length; i++) {
            sumr += imageHist.get(0)[i];
            int valr = (int) (sumr * scale_factor); // zwraca wartosc dla koloru czerwonego
            if(valr > 255) {
                rhistogram[i] = 255;
            }
            else rhistogram[i] = valr;
 
            sumg += imageHist.get(1)[i];
            int valg = (int) (sumg * scale_factor);
            if(valg > 255) {
                ghistogram[i] = 255;
            }
            else ghistogram[i] = valg;
 
            sumb += imageHist.get(2)[i];
            int valb = (int) (sumb * scale_factor);
            if(valb > 255) {
                bhistogram[i] = 255;
            }
            else bhistogram[i] = valb;
        }
 
        imageLUT.add(rhistogram);
        imageLUT.add(ghistogram);
        imageLUT.add(bhistogram);
 
        return imageLUT;
 
    }
 
   //Metoda zwraca histogramy dla poszczegolnych skladowych R, G, B
    public static ArrayList<int[]> imageHistogram(BufferedImage input) {
 
        int[] rhistogram = new int[256];
        int[] ghistogram = new int[256];
        int[] bhistogram = new int[256];
 
        for(int i=0; i<rhistogram.length; i++) rhistogram[i] = 0;
        for(int i=0; i<ghistogram.length; i++) ghistogram[i] = 0;
        for(int i=0; i<bhistogram.length; i++) bhistogram[i] = 0;
              
        for(int i=0; i<input.getWidth(); i++) {
            for(int j=0; j<input.getHeight(); j++) {
 
                int red = new Color(input.getRGB (i, j)).getRed();
                int green = new Color(input.getRGB (i, j)).getGreen();
                int blue = new Color(input.getRGB (i, j)).getBlue();
 
                // Zwiększanie wartości kolorow
                rhistogram[red]++; ghistogram[green]++; bhistogram[blue]++;
 
            }
        }
        
        ArrayList<int[]> hist = new ArrayList<int[]>();
        hist.add(rhistogram);
        hist.add(ghistogram);
        hist.add(bhistogram);
       
        return hist;
 
    }
 
    // Wpisanie trzech wartosci kolorow w jeden piksel
    private static int colorToRGB(int red, int green, int blue) {
 
        int newPixel = 0;
        newPixel = (red * 65536) + (green * 256) + blue;
        return newPixel;
 
    }
}
